﻿// Server Message

using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Collections;


namespace chat_client_sp
{

    /// <summary>
    /// FileDataMessage is a LTV message, the length include legth of T and V.
    /// i.e. 
    /// 0x00000006  - length
    /// 0x00000001  - type (4byte) 
    /// following are value bytes
    ///     - 0x00000009  - namesize (4 byte)
    ///     - 0x31..chars.....  - filename (namesize bytes, 9 bytes)
    ///     - 0xfffffff   - filedata buffer (length - 4 - namesize bytes)
    /// </summary>
    public class FileDataMessage : BaseMessage
    {
        // all in the Value buffer
        public int NameSize;
        public string FileName;
        public byte[] FileData;

        public FileDataMessage()
        {
        }
        /// <summary>
        /// construct from filename, filedata
        /// </summary>
        /// <param name="_data"></param>
        public FileDataMessage(string filename, byte[] filedata)
        {
            MessageType = (int)MessageTypeEnum.FILEDATE;
            NameSize = filename.Length;
            FileName = filename;
            FileData = new byte[filedata.Length];
            filedata.CopyTo(FileData, 0);
            
            // msgtype + namesize + filename + filedata
            Length = 4 + 4 + NameSize + filedata.Length;

            Value = new byte[Length];
            Buffer.BlockCopy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(NameSize)), 0, Value, 0, 4);
            Buffer.BlockCopy(Encoding.ASCII.GetBytes(FileName), 0, Value, 4, NameSize);
            Buffer.BlockCopy(FileData, 0, Value, 4 + NameSize, FileData.Length);
        }


        /// <summary>
        /// parse from raw packet
        /// </summary>
        /// <param name="_data"></param>
        public static new FileDataMessage Parse(byte[] _raw)
        {
            BaseMessage msg1 = BaseMessage.Parse(_raw);
            FileDataMessage filemsg = new FileDataMessage();
            filemsg.Length = msg1.Length; ;
            filemsg.MessageType = msg1.MessageType;
            filemsg.Value = msg1.Value;
            msg1 = null;   // release msg1

            byte[] namesize_buf = new byte[4];
            Array.Copy(filemsg.Value, 0, namesize_buf, 0, 4);
            filemsg.NameSize = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(namesize_buf, 0));

            byte[] name_buf = new byte[filemsg.NameSize];
            Array.Copy(filemsg.Value, 4, name_buf, 0, filemsg.NameSize);
            filemsg.FileName = Encoding.ASCII.GetString(name_buf);

            int filesize = filemsg.Value.Length - 4 - filemsg.NameSize;
            filemsg.FileData = new byte[filesize];
            Array.Copy(filemsg.Value, 4 + filemsg.NameSize, filemsg.FileData, 0, filesize);
            return filemsg;
        }

        public override void Dump()
        {
            Console.WriteLine("    Message Length: {0}", Length);
            Console.WriteLine("    Type  : {0}", Enum.GetName(typeof(MessageTypeEnum), MessageType));
            Console.WriteLine("    NameSize: {0}", NameSize);
            Console.WriteLine("    Name: {0}", FileName);
            Console.WriteLine("    FileSize: {0}B", FileData.Length);
            Console.WriteLine("    File Data: ");
            foreach (byte b in FileData)
            {
                Console.Write("{0:X}, ", b);
            }
            Console.WriteLine();

        }
    }


    public class FileDataMessageUnitTest
    {
        public static void TestConstructFromBinaryPacket()
        {
            Console.WriteLine("TestConstructFromBinaryPacket");

            // 1) contruct from raw packet 
            byte[] buf2 = new byte[] { 
                0, 0, 0, 0x15,              // length 
                0, 0, 0, 0x01,              // msg type
                0, 0, 0, 0x9,               // value - namesize
                0x70, 0x68, 0x6F, 0x6E, 0x65, 0x2E, 0x74, 0x78, 0x74,   // value - name 
                0xff, 0xff, 0xff, 0xff };   // value - filedata
            BaseMessage fmsg2 = FileDataMessage.Parse(buf2);
            fmsg2.Dump();
            fmsg2.DumpHex();


        }

        /// <summary>
        /// the phone file hex dump out should be:
        /// 0 0 0 15 0 0 0 1 0 0 0 9 70 68 6F 6E 65 2E 74 78 74 FF FF FF FF
        /// field breakdown is:
        /// Message Length: 21
        /// NameSize: 9
        /// Name: phone.txt
        /// FileSize: 4B
        /// File Data: FF, FF, FF, FF,
        /// </summary>
        public static void TestConstructFromFiels()
        {
            // 1) constrcut from type and value
            Console.WriteLine();
            Console.WriteLine("TestConstructFromFiels");
            byte[] filedata = new byte[] { 0xff, 0xff, 0xff, 0xff };
            BaseMessage fmsg3 = new FileDataMessage("phone.txt", filedata);
            fmsg3.Dump();
            fmsg3.DumpHex();

            // constrcut reversely and see if it's correct
            BaseMessage fmsg4 = FileDataMessage.Parse(fmsg3.GetBytes());
            fmsg4.Dump();

        }

        public static void TestQueueMsg()
        {
            Queue queue = new Queue();
            BaseMessage msg1 = new BaseMessage((int)MessageTypeEnum.JOIN, new byte[] {0xff, 0xff});
            BaseMessage msg2 = new FileDataMessage("test", new byte[] { 0xff, 0xff });
            queue.Enqueue(msg1);
            queue.Enqueue(msg2);

            BaseMessage dmsg1 = (BaseMessage)queue.Dequeue();
            dmsg1.Dump();
            BaseMessage dmsg2 = (BaseMessage)queue.Dequeue();
            dmsg2.Dump();

            //foreach (SFMessage m in queue)
            //{
            //    m.Dump();
            //}

        }

    }
}
